import random
from lxml import etree

import requests
import json
from matplotlib import pyplot as plt
import numpy


class BaiDuBar:
    """
    百度贴吧爬虫类
    """

    def __init__(self, bar_name):
        """
        初始化方法
        """
        # 1. 确定访问地址
        self.url = "https://tieba.baidu.com/f?kw=" + bar_name + "&ie=utf-8&pn={}"
        # 2. 确定请求头信息
        self.header = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"
        }
        # 3. 将所有的请求的url放到一个请求列表中
        # 后续我们只需要遍历这个列表,将构造好的url取出即可
        # 假设构造10页---10个url
        self.urls = [self.url.format(i * 50) for i in range(10)]
        # 保存贴吧的名字
        self.name = bar_name

    def get_response(self, url):
        """
        发送请求并获取响应
        :return: 响应体中内容(html页面)
        """
        return requests.get(url=url, headers=self.header).content.decode()

    def parse_response(self):
        """
        解析数据
        :return:
        """
        pass

    def save(self, content, page):
        """
        保存解析后的数据
        :return:
        """
        with open(f'baidu/{self.name}吧-第{page}页', 'w', encoding='utf-8') as f:
            # 文件的写入
            f.write(content)

    def run(self):
        """
        爬虫启动程序
        :return:
        """
        print("百度贴吧爬虫已启动---------------->")
        # 如果在__init__中我们将所有的地址构造好之后
        # 遍历所有的请求地址
        for url in self.urls:
            # 1. 发送请求并获取响应
            content = self.get_response(url)
            # 2. 保存页面内容
            self.save(content, self.urls.index(url) + 1)


class DouBan:
    """
    豆瓣爬虫
    """
    movie_tag_url = "https://movie.douban.com/j/search_tags?type=movie&source=index"
    tv_tag_url = "https://movie.douban.com/j/search_tags?type=tv&source=index"
    # 用来存储电影以及电视剧对应的tag
    tag = {
        "movie": [],
        "tv": []
    }

    @classmethod
    def get_tags(cls, url):
        # 发送请求
        tag_json = requests.get(url=url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                                                                "AppleWebKit/537.36 (KHTML, like Gecko) "
                                                                "Chrome/85.0.4183.83 Safari/537.36"})
        # 将得到的json串转换成python字典对象
        tag_dict = json.loads(tag_json.content.decode())
        if url == DouBan.movie_tag_url:
            DouBan.tag["movie"] = tag_dict["tags"]
        else:
            DouBan.tag["tv"] = tag_dict["tags"]

    def __init__(self, tag, t="movie"):
        # 获取当前热门电影
        # https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0
        # 获取当前热门电视剧
        # https://movie.douban.com/j/search_subjects?type=tv&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0
        # 1. 确认访问的url
        self.url = "https://movie.douban.com/j/search_subjects?type=" \
                   + t + \
                   "&tag=" + tag + "&page_limit=50&page_start={}"
        # 2. 请求头
        self.header = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                          "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"
        }
        # 3. 数据源
        self.sources = []
        # 4. 保存
        self.t = t

    def get_response(self, url):
        """
        发送请求并获取响应
        :param url: 请求地址
        :return:    响应体内容
        """
        delegate = {
            "HTTP": "171.35.223.124:9999"
        }
        return requests.get(url=url, headers=self.header, proxies=delegate).content.decode()

    def parse_response(self, content):
        """
        解析数据
        :param content: 数据
        :return:
        """
        # 0. 先转换成python字典对象
        data = json.loads(content)
        # 1. 遍历
        for film in data["subjects"]:
            # 1.1 创建数据字典存储提取的数据
            film_dict = dict()
            film_dict["评分"] = film["rate"]
            film_dict["电影名"] = film["title"]
            # 1.2 添加到数据源中
            self.sources.append(film_dict)

    def save(self):
        """
        保存数据的方法
        @ 写入文件中(.txt .json, csv)
        @ 写入数据库(mysql sql 关系型数据库)
        @ NOSql(mongodb, redis)
        :return:
        """
        d = {"data": self.sources}
        # 我们可以将python类型的字典对象转换成json字符串
        with open('data/film.json', 'w', encoding='utf-8') as f:
            # 写入文件
            f.write(json.dumps(d, ensure_ascii=False, indent=4))

        # with open('data/film.txt', 'a', encoding='utf-8') as f:
        #     # 写入文件
        #     f.write(json.dumps(d, ensure_ascii=False, indent=4))

    def show_line(self, x, y, start=0, end=10):
        """
        显示图示
        @x轴: 电影或电视剧的名称
        @y轴: 评分
        :return:
        """
        # 1. 设置中文
        plt.rcParams["font.sans-serif"] = ['SimHei']
        # 2. 设置figure的大小
        plt.figure(figsize=(30, 10), dpi=120)
        # 3. 设置刻度
        x_axis = x[start:end]
        y_axis = y[start:end]
        # 4. 调整x轴新刻度
        # 4.1 因为mp 轴不能显示中文, 索引我们采取替换的方式, 让两个列表分别对应上
        plt.xticks(list(range(len(x_axis))), x_axis)
        # 5. 绘制
        plt.plot(x_axis, y_axis, label=self.t, marker='o', markerfacecolor='#66CD00')
        plt.grid()
        # # 6. 显示
        plt.legend()
        plt.show()
        # # 7. 保存生成的figure
        plt.savefig(f'image/{self.t}.png')

    def show_bar(self, x, y, start=0, end=10):
        """
        显示图示
        @x轴: 电影或电视剧的名称
        @y轴: 评分
        :return:
        """
        # 1. 设置中文
        plt.rcParams["font.sans-serif"] = ['SimHei']
        # 2. 设置figure的大小
        plt.figure(figsize=(30, 10), dpi=120)
        # 3. 设置刻度
        x_axis = x[start:end]
        y_axis = y[start:end]
        # 4. 调整x轴新刻度
        # 4.1 因为mp 轴不能显示中文, 索引我们采取替换的方式, 让两个列表分别对应上
        plt.xticks(list(range(len(x_axis))), x_axis)
        plt.yticks(range(round(min(y_axis)), round(max(y_axis)) + 1))
        # 5. 绘制条形图
        plt.bar(x_axis, y_axis, width=0.5, label='热门电影')
        plt.grid()
        # # 6. 显示
        plt.legend()
        plt.show()
        # # 7. 保存生成的figure
        plt.savefig(f'image/{self.t}.png')

    def run(self):
        print("豆瓣爬虫启动了-------------->")
        # 构造请求地址
        for index in range(2):
            url = self.url.format(index * 50)
            # 发送请求并获取响应
            content = self.get_response(url)
            # 解析数据(你要提取的数据)
            self.parse_response(content)
        # 保存数据到本地
        self.save()


class KuaiDelegate:
    """
    @xpath案例: 快代理网站代理的提取
    """
    pass


class MovieEnum:
    """
    @电影类型 仿照枚举类型
    """
    plot = 0  # 剧情
    comedy = 1  # 戏剧
    action = 2  # 动作
    love = 3  # 爱情
    science = 4  # 科幻
    terror = 8  # 恐怖片


class DYTT:
    """


    @电影天堂 二级页面解析
    """

    def __init__(self, movie_type=MovieEnum.plot):
        # 请求地址
        self.url = "https://www.dy2018.com/" + str(movie_type) + "/index_{}.html"
        # 请求头
        self.headers = [
            {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101"},
            {"User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) "
                           "AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"},
            {"User-Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)"}
        ]
        # 数据源
        self.sources = []

    def get_response(self, url):
        """
        发送请求并获取响应
        :param url: 请求地址
        :return: 响应体内容
        """
        return requests.get(url=url, headers=self.headers[random.randint(0, len(self.headers) - 1)]).content.decode(
            'gbk')

    def parse_list_response(self, data):
        """
        解析列表页数据
        :return:
        """
        # print(data)
        # 创建查找对象
        obj = etree.HTML(data)
        # 提取数据
        table_nodes = obj.xpath('//div[@class="co_content8"]/ul//table')
        if len(table_nodes) == 0:
            print("根据xpath没有提取到任何数据节点!")
            return
        # 提取数据
        for t in table_nodes:
            # 创建数据字典
            film = dict()
            # 提取电影名称
            film['name'] = t.xpath('.//td[@height="26"]//a[last()]/@title')[0]
            # 获取详情连接
            detail_url = "https://www.dy2018.com" + t.xpath('.//td[@height="26"] //a[last()]/@href')[0]
            # 解析二级面内容
            self.parse_detail_response(detail_url, film)

    def parse_detail_response(self, url, film):
        """
        解析详情页数据
        :return:
        """
        # 发送请求获取响应
        data = self.get_response(url)
        # 创建解析对象
        obj = etree.HTML(data)
        # 提取下载地址
        film['download'] = obj.xpath('//div[@id="downlist"]//a/@href')[0]
        # 将处理好得电影字典存入数据源中
        self.sources.append(film)

    def save(self):
        """
        存储文件
        :return:
        """
        pass

    def run(self, page_number):
        # 1. 处理请求地址
        for index in range(1, page_number):
            # 拼接请求地址
            url = self.url.format(index)
            if index == 1:
                url = self.url.format(index).split('_')[0] + '.html'
            # 2. 发送请求并获取响应
            content = self.get_response(url)
            # 3. 解析列表页数据
            self.parse_list_response(content)
        print(self.sources)


class DyttNew:
    """
    @电影天堂 二级页面解析
    """

    def __init__(self, movie_type=MovieEnum.plot):
        # 请求地址
        self.url = "https://www.dy2018.com/" + str(movie_type) + "/index_{}.html"
        # 请求头
        self.headers = [
            {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101"},
            {"User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) "
                           "AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"},
            {"User-Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)"}
        ]

    def get_response(self, url):
        """
        发送请求并获取响应
        :param url: 请求地址
        :return: 响应体内容
        """
        return requests.get(url=url, headers=self.headers[random.randint(0, len(self.headers) - 1)]).content.decode(
            'gbk')

    def parse_list_response(self, data):
        """
        解析列表页数据
        :return:
        """
        # print(data)
        # 创建查找对象
        obj = etree.HTML(data)
        # 提取数据
        table_nodes = obj.xpath('//div[@class="co_content8"]/ul//table')
        if len(table_nodes) == 0:
            print("根据xpath没有提取到任何数据节点!")
            return

        # 创建数据字典
        film = dict()
        # 提取数据
        for t in table_nodes:
            # 提取电影名称
            film['name'] = t.xpath('.//td[@height="26"]//a[last()]/@title')[0]
            # 获取详情连接
            detail_url = "https://www.dy2018.com" + t.xpath('.//td[@height="26"]//a[last()]/@href')[0]
            # 解析二级面内容
            yield self.parse_detail_response(detail_url, film)

    def parse_detail_response(self, url, film):
        """
        解析详情页数据
        :return:
        """
        # 发送请求获取响应
        data = self.get_response(url)
        # 创建解析对象
        obj = etree.HTML(data)
        # 提取下载地址
        film['download'] = obj.xpath('//div[@id="downlist"]//a/@href')[0]
        # 返回
        return film

    def save(self, data):
        """
        存储文件
        :return:
        """
        print(f"--------------写入数据中--------------{data}")

    def run(self, page_number):
        # 1. 处理请求地址
        for index in range(1, page_number):
            # 拼接请求地址
            url = self.url.format(index)
            if index == 1:
                url = self.url.format(index).split('_')[0] + '.html'
            # 2. 发送请求并获取响应
            content = self.get_response(url)
            # 3. 解析列表页数据
            for data in self.parse_list_response(content):
                self.save(data)
